/* 
 * MacHash - A simple utility that takes a filename or a string and creates
 * a digest of the contents using the select hash type.  MacHash acts as a 
 * Cocoa UI to the OpenSSL hash libraries.
 *
 * Copyright (C) 2006 Rick Russell - machash at idatasys dot com
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */


#import "Hash.h"



@implementation Hash

- (id)init
{
	fileBufferSize = 4096;
	[super init];
	return self;
}

- (NSString *)createStringHash:(NSString *)textInput hashType:(NSString *)digestType
{

	long inputLen;
	unsigned char *input;
	
	
	inputLen = [textInput length];
	input = (unsigned char *)[textInput UTF8String];
	NSLog(@"Converted String: %s and the length is %d", input, inputLen);
	
	if([digestType isEqual:@"MD2"])
	{
		[self createStringMD2Digest:input length:inputLen];
	}	
	
	if([digestType isEqual:@"MD4"])
	{
		[self createStringMD4Digest:input length:inputLen];
	}
	
	if([digestType isEqual:@"MD5"])
	{
		[self createStringMD5Digest:input length:inputLen];
	}
	
	if([digestType isEqual:@"SHA1"])
	{
		[self createStringSHA1Digest:input length:inputLen];
	}
	
	return [self description]; 
		
}

- (NSString *)createFileHash:(NSString *)filePath hashType:(NSString *)digestType
{
	NSFileHandle *file;
	
	// Get the file handle
	file = [NSFileHandle fileHandleForReadingAtPath:filePath];

	if([digestType isEqual:@"MD2"])
	{
		[self createFileMD2Digest:file];
	}
		
	if([digestType isEqual:@"MD4"])
	{
		[self createFileMD4Digest:file];
	}
		
	if([digestType isEqual:@"MD5"])
	{
		[self createFileMD5Digest:file];
	}
	
	if([digestType isEqual:@"SHA1"])
	{
		[self createFileSHA1Digest:file];
	}
	
	[file closeFile];
	
	return [self description]; 
		
}

- (void)createStringMD2Digest:(unsigned char *)input length:(long)inputLen 
{

		MD2_CTX ctx;

		digestLen = MD2_DIGEST_LENGTH;
		[self allocDigest];

		MD2_Init(&ctx);
		MD2_Update(&ctx,input,inputLen);
		MD2_Final(&(digest[0]), &ctx);

}

- (void)createFileMD2Digest:(NSFileHandle *)file 
{
		NSData *fileData;
		unsigned char buff[fileBufferSize];
		MD2_CTX ctx;

		digestLen = MD2_DIGEST_LENGTH;
		[self allocDigest];

		MD2_Init(&ctx);
		
		fileData = [file readDataOfLength:fileBufferSize];
		
		while([fileData length] > 0)
		{
			[fileData getBytes:buff];
			MD2_Update(&ctx,buff,[fileData length]);

			fileData = [file readDataOfLength:fileBufferSize];
		}
		
		MD2_Final(&(digest[0]), &ctx);

}

- (void)createStringMD4Digest:(unsigned char *)input length:(long)inputLen 
{

		MD4_CTX ctx;

		digestLen = MD4_DIGEST_LENGTH;
		[self allocDigest];

		MD4_Init(&ctx);
		MD4_Update(&ctx,input,inputLen);
		MD4_Final(&(digest[0]), &ctx);

}

- (void)createFileMD4Digest:(NSFileHandle *)file 
{
		NSData *fileData;
		unsigned char buff[fileBufferSize];
		MD4_CTX ctx;

		digestLen = MD4_DIGEST_LENGTH;
		[self allocDigest];

		MD4_Init(&ctx);
		
		fileData = [file readDataOfLength:fileBufferSize];
		
		while([fileData length] > 0)
		{
			[fileData getBytes:buff];
			MD4_Update(&ctx,buff,[fileData length]);

			fileData = [file readDataOfLength:fileBufferSize];
		}
		
		MD4_Final(&(digest[0]), &ctx);

}

- (void)createStringMD5Digest:(unsigned char *)input length:(long)inputLen 
{

		MD5_CTX ctx;

		digestLen = MD5_DIGEST_LENGTH;
		[self allocDigest];

		MD5_Init(&ctx);
		MD5_Update(&ctx,input,inputLen);
		MD5_Final(&(digest[0]), &ctx);

}

- (void)createFileMD5Digest:(NSFileHandle *)file 
{
		NSData *fileData;
		unsigned char buff[fileBufferSize];
		MD5_CTX ctx;

		digestLen = MD5_DIGEST_LENGTH;
		[self allocDigest];

		MD5_Init(&ctx);
		
		fileData = [file readDataOfLength:fileBufferSize];
		
		while([fileData length] > 0)
		{
			[fileData getBytes:buff];
			MD5_Update(&ctx,buff,[fileData length]);

			fileData = [file readDataOfLength:fileBufferSize];
		}
		
		MD5_Final(&(digest[0]), &ctx);

}

- (void)createStringSHA1Digest:(unsigned char *)input length:(long)inputLen 
{
		SHA_CTX ctx;

		
		digestLen = SHA_DIGEST_LENGTH;
		[self allocDigest];
		
		SHA1_Init(&ctx);
		SHA1_Update(&ctx,input,inputLen);
		SHA1_Final(&(digest[0]), &ctx);

}

- (void)createFileSHA1Digest:(NSFileHandle *)file 
{
		NSData *fileData;
		unsigned char buff[fileBufferSize];
		SHA_CTX ctx;

		digestLen = SHA_DIGEST_LENGTH;
		[self allocDigest];

		SHA1_Init(&ctx);
		
		fileData = [file readDataOfLength:fileBufferSize];
		while([fileData length] > 0)
		{
			[fileData getBytes:buff];
			SHA1_Update(&ctx,buff,[fileData length]);
			fileData = [file readDataOfLength:fileBufferSize];
		}
		
		SHA1_Final(&(digest[0]), &ctx);


}

- (void)freeDigest
{
	if(digest != 0)
	{
		free(digest);
	}
}

- (void)allocDigest
{
	[self freeDigest];
	digest = malloc(digestLen);
	if(digest == 0)
	{
		NSLog(@"Malloc of digest failed");
		exit(-1);
	}
}

- (void)dealloc
{
	NSLog(@"Hash dealloc");
	// Make sure that we free the memeory used by malloc
	
	[self freeDigest];
	[super dealloc];

}

- (NSString *)description
{
	NSString *result = @"";
	int i;
	
	for(i = 0; i < digestLen; i++)
	{
		result = [result stringByAppendingFormat:@"%02x",digest[i]];
	}
	
	return result;
}	

/**
 *
 * Accessor Methods
 *
 */
- (int)fileBufferSize
{
	return fileBufferSize;
}

- (void)setFileBufferSize:(int)size
{
	fileBufferSize = size;
}
	
@end
